package com.smart.community.property.utils;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;

/**
 * 月份区间重叠检测工具类
 * 
 * @author Wu.Liang
 * @since 2025-01-30
 * @version 1.0.0
 */
@Slf4j
public class MonthRangeUtils {

    private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM");

    /**
     * 月份区间数据类
     */
    @Data
    public static class MonthRange {
        private YearMonth startMonth;
        private YearMonth endMonth;
        
        public MonthRange(String startMonth, String endMonth) {
            this.startMonth = YearMonth.parse(startMonth, MONTH_FORMATTER);
            this.endMonth = YearMonth.parse(endMonth, MONTH_FORMATTER);
        }
        
        public MonthRange(String singleMonth) {
            this.startMonth = YearMonth.parse(singleMonth, MONTH_FORMATTER);
            this.endMonth = this.startMonth;
        }
        
        public MonthRange(YearMonth startMonth, YearMonth endMonth) {
            this.startMonth = startMonth;
            this.endMonth = endMonth;
        }
        
        /**
         * 获取月份数量
         */
        public int getMonthCount() {
            return (int) startMonth.until(endMonth, java.time.temporal.ChronoUnit.MONTHS) + 1;
        }
        
        /**
         * 检查是否包含指定月份
         */
        public boolean contains(YearMonth month) {
            return !month.isBefore(startMonth) && !month.isAfter(endMonth);
        }
        
        @Override
        public String toString() {
            if (startMonth.equals(endMonth)) {
                return startMonth.format(MONTH_FORMATTER);
            }
            return startMonth.format(MONTH_FORMATTER) + " ~ " + endMonth.format(MONTH_FORMATTER);
        }
    }

    /**
     * 检查两个计费周期是否存在重叠
     * 
     * @param period1 计费周期1 (格式: "2025-01 ~ 2025-03" 或 "2025-01")
     * @param period2 计费周期2 (格式: "2025-01 ~ 2025-03" 或 "2025-01")
     * @return true-存在重叠，false-无重叠
     */
    public static boolean hasOverlap(String period1, String period2) {
        if (!StringUtils.hasText(period1) || !StringUtils.hasText(period2)) {
            log.warn("计费周期为空，period1: {}, period2: {}", period1, period2);
            return false;
        }
        
        try {
            MonthRange range1 = parseMonthRange(period1);
            MonthRange range2 = parseMonthRange(period2);
            
            return hasOverlap(range1, range2);
        } catch (Exception e) {
            log.error("检查计费周期重叠失败，period1: {}, period2: {}", period1, period2, e);
            return false;
        }
    }

    /**
     * 检查两个月份区间是否存在重叠
     * 
     * @param range1 月份区间1
     * @param range2 月份区间2
     * @return true-存在重叠，false-无重叠
     */
    public static boolean hasOverlap(MonthRange range1, MonthRange range2) {
        if (range1 == null || range2 == null) {
            return false;
        }
        
        // 检查重叠：range1的结束月份 >= range2的开始月份 且 range1的开始月份 <= range2的结束月份
        boolean hasOverlap = !range1.getEndMonth().isBefore(range2.getStartMonth()) && 
                           !range1.getStartMonth().isAfter(range2.getEndMonth());
        
        log.debug("月份区间重叠检查: {} vs {}, 结果: {}", range1, range2, hasOverlap);
        return hasOverlap;
    }

    /**
     * 解析计费周期字符串为月份区间对象
     * 
     * @param billingPeriod 计费周期字符串 (格式: "2025-01 ~ 2025-03" 或 "2025-01")
     * @return 月份区间对象
     * @throws IllegalArgumentException 如果格式不正确
     */
    public static MonthRange parseMonthRange(String billingPeriod) {
        if (!StringUtils.hasText(billingPeriod)) {
            throw new IllegalArgumentException("计费周期不能为空");
        }
        
        billingPeriod = billingPeriod.trim();
        
        // 检查是否包含分隔符 "~"
        if (billingPeriod.contains("~")) {
            String[] parts = billingPeriod.split("~");
            if (parts.length != 2) {
                throw new IllegalArgumentException("计费周期格式错误，应为 'yyyy-MM ~ yyyy-MM' 或 'yyyy-MM'");
            }
            
            String startMonth = parts[0].trim();
            String endMonth = parts[1].trim();
            
            try {
                return new MonthRange(startMonth, endMonth);
            } catch (DateTimeParseException e) {
                throw new IllegalArgumentException("计费周期月份格式错误，应为 'yyyy-MM' 格式", e);
            }
        } else {
            // 单月格式
            try {
                return new MonthRange(billingPeriod);
            } catch (DateTimeParseException e) {
                throw new IllegalArgumentException("计费周期月份格式错误，应为 'yyyy-MM' 格式", e);
            }
        }
    }

    /**
     * 验证计费周期格式是否正确
     * 
     * @param billingPeriod 计费周期字符串
     * @return true-格式正确，false-格式错误
     */
    public static boolean isValidBillingPeriod(String billingPeriod) {
        if (!StringUtils.hasText(billingPeriod)) {
            return false;
        }
        
        try {
            parseMonthRange(billingPeriod);
            return true;
        } catch (Exception e) {
            log.debug("计费周期格式验证失败: {}", billingPeriod, e);
            return false;
        }
    }

    /**
     * 获取重叠的月份列表
     * 
     * @param period1 计费周期1
     * @param period2 计费周期2
     * @return 重叠的月份列表
     */
    public static List<YearMonth> getOverlappingMonths(String period1, String period2) {
        List<YearMonth> overlappingMonths = new ArrayList<>();
        
        if (!hasOverlap(period1, period2)) {
            return overlappingMonths;
        }
        
        try {
            MonthRange range1 = parseMonthRange(period1);
            MonthRange range2 = parseMonthRange(period2);
            
            // 计算重叠区间的开始和结束月份
            YearMonth overlapStart = range1.getStartMonth().isAfter(range2.getStartMonth()) ? 
                                   range1.getStartMonth() : range2.getStartMonth();
            YearMonth overlapEnd = range1.getEndMonth().isBefore(range2.getEndMonth()) ? 
                                 range1.getEndMonth() : range2.getEndMonth();
            
            // 生成重叠月份列表
            YearMonth current = overlapStart;
            while (!current.isAfter(overlapEnd)) {
                overlappingMonths.add(current);
                current = current.plusMonths(1);
            }
            
            log.debug("计费周期重叠月份: {} vs {}, 重叠月份: {}", period1, period2, overlappingMonths);
        } catch (Exception e) {
            log.error("获取重叠月份失败，period1: {}, period2: {}", period1, period2, e);
        }
        
        return overlappingMonths;
    }

    /**
     * 计算月份数量
     * 
     * @param billingPeriod 计费周期
     * @return 月份数量
     */
    public static int calculateMonthCount(String billingPeriod) {
        try {
            MonthRange range = parseMonthRange(billingPeriod);
            return range.getMonthCount();
        } catch (Exception e) {
            log.error("计算月份数量失败，billingPeriod: {}", billingPeriod, e);
            return 0;
        }
    }

    /**
     * 检查计费周期是否有效（开始月份不能晚于结束月份）
     * 
     * @param billingPeriod 计费周期
     * @return true-有效，false-无效
     */
    public static boolean isValidMonthRange(String billingPeriod) {
        try {
            MonthRange range = parseMonthRange(billingPeriod);
            return !range.getStartMonth().isAfter(range.getEndMonth());
        } catch (Exception e) {
            return false;
        }
    }
}
